package ru.stepuk.modern;

import ru.stepuk.modern.nodes.Node;
import edu.uci.ics.jung.algorithms.layout.Layout;
import edu.uci.ics.jung.algorithms.layout.StaticLayout;
import edu.uci.ics.jung.graph.DirectedSparseGraph;
import edu.uci.ics.jung.visualization.RenderContext;
import edu.uci.ics.jung.visualization.VisualizationViewer;
import edu.uci.ics.jung.visualization.control.CrossoverScalingControl;
import edu.uci.ics.jung.visualization.control.EditingModalGraphMouse;
import edu.uci.ics.jung.visualization.control.ModalGraphMouse;
import edu.uci.ics.jung.visualization.decorators.EdgeShape;
import java.awt.Color;
import java.awt.Dimension;
import java.util.Calendar;
import org.apache.commons.collections15.Factory;
import org.picocontainer.DefaultPicoContainer;
import org.picocontainer.MutablePicoContainer;
import org.picocontainer.Parameter;
import org.picocontainer.parameters.ComponentParameter;
import ru.stepuk.modern.nodes.NodeFactory;
import ru.stepuk.modern.util.*;
import ru.stepuk.modern.gui.PopupMenus;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import org.picocontainer.behaviors.Caching;
import ru.stepuk.modern.distributions.DistributionFactory;
import ru.stepuk.modern.generators.MersenneTwister;
import ru.stepuk.modern.util.NodeLabelTransformer;
import ru.stepuk.modern.util.PathLabelTransformer;

/**
 *
 * @author ivan
 */
public class ApplicationFactory implements Factory<Application> {

    private static final int CANVAS_WIDTH = 1024;
    private static final int CANVAS_HEIGHT = 1024;
    private static final Color CANVAS_BACKGROUND = new Color(0XFFFFEE);

    public Application create() {

        //TODO Handle this laf exceptions
        try {
            UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
        } catch (ClassNotFoundException ex) {
            Logger.getLogger(Application.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            Logger.getLogger(Application.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            Logger.getLogger(Application.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnsupportedLookAndFeelException ex) {
            Logger.getLogger(Application.class.getName()).log(Level.SEVERE, null, ex);
        }

        MutablePicoContainer pico = new DefaultPicoContainer(new Caching());

        pico.addComponent(DirectedSparseGraph.class);
        pico.addComponent(Layout.class, StaticLayout.class);
        pico.addComponent(new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT));
        pico.addComponent(Model.class);
        pico.addComponent(Controller.class);
        pico.addComponent(CrossoverScalingControl.class);
        pico.addComponent(Timeline.class);
        pico.addComponent(Application.class);
        pico.addComponent(DistributionFactory.class);
        //TODO WARNING!!! BEware of negative seeds!!!1
        pico.addComponent(new MersenneTwister((int) Calendar.getInstance().getTimeInMillis() >>> 1));

        VisualizationViewer<Node, Path> vv =
                new VisualizationViewer<Node, Path>(pico.getComponent(Layout.class));
        vv.setBackground(CANVAS_BACKGROUND);

        vv.setBounds(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
        vv.getRenderContext().setEdgeShapeTransformer(new EdgeShape.Line<Node, Path>());
        vv.getRenderContext().setVertexShapeTransformer(new NodeShapeTransformer());
        vv.getRenderContext().setVertexIconTransformer(new NodeIconTransformer());
        vv.getRenderContext().setEdgeLabelTransformer(new PathLabelTransformer());
        vv.getRenderContext().setVertexLabelTransformer(new NodeLabelTransformer());

        pico.addComponent(NodeFactory.class, NodeFactory.class);
        pico.addComponent(PathFactory.class, PathFactory.class);
        pico.addComponent(RenderContext.class, vv.getRenderContext());
        pico.addComponent(EditingModalGraphMouse.class, EditingModalGraphMouse.class, new Parameter[]{
                    new ComponentParameter(),
                    new ComponentParameter(NodeFactory.class),
                    new ComponentParameter(PathFactory.class)
                });
        EditingModalGraphMouse mo = pico.getComponent(EditingModalGraphMouse.class);
        mo.remove(mo.getPopupEditingPlugin());
        pico.addComponent(PopupMenuPlugin.class);
        pico.addComponent(PopupMenus.NodeMenu.class);
        pico.addComponent(PopupMenus.PathMenu.class);

        mo.add(pico.getComponent(PopupMenuPlugin.class));
        mo.setMode(ModalGraphMouse.Mode.TRANSFORMING);

        vv.setGraphMouse(mo);

        pico.addComponent(vv);

        return pico.getComponent(Application.class);
    }
}
